home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************************
- #
- # scanner.c
- #
- # This segment handles scanner calls.
- #
- # Author(s): Michael Marinkovich
- # Apple Developer Technical Support
- # marink@apple.com
- #
- # Modification History:
- #
- # 2/10/96 MWM Initial coding
- #
- # Copyright © 1992-96 Apple Computer, Inc., All Rights Reserved
- #
- #
- # You may incorporate this sample code into your applications without
- # restriction, though the sample code has been provided "AS IS" and the
- # responsibility for its operation is 100% yours. However, what you are
- # not permitted to do is to redistribute the source as "DSC Sample Code"
- # after having made changes. If you're going to re-distribute the source,
- # we require that you make it clear in the source that the code was
- # descended from Apple Sample Code, but that you've made changes.
- #
- *************************************************************************************/
-
- #include <Controls.h>
- #include <Events.h>
- #include <ToolUtils.h>
- #include <Gestalt.h>
- #include <OSUtils.h>
- #include <Palettes.h>
-
- #include "App.h"
- #include "Proto.h"
-
-
- //----------------------------------------------------------------------
- //
- // DoNewScan - main entry point for scanning
- //
- //
- //----------------------------------------------------------------------
-
- OSErr DoNewScan(CGrafPtr *dstPort)
- {
- OSErr err = noErr;
- ScStdFeaturesRec scannerInfo;
- ScResPtr lineArtRes;
- ScResPtr halfToneRes;
- ScResPtr grayScaleRes;
- ScResPtr biLevelColorRes;
- ScResPtr fullColorRes;
- ScHalfTonePtr halfToneNames;
- CTabHandle cTab = nil;
- UserSettings userSettings;
- Rect scanRect;
- UInt32 pixelDepth;
- Fixed height;
- Fixed width;
-
- if (dstPort != nil)
- {
- // get supported resolutions and halftone names from scanner.
- err = GetScannerInfo(&scannerInfo, &lineArtRes,
- &halfToneRes, &grayScaleRes,
- &biLevelColorRes, &fullColorRes,
- &halfToneNames);
-
- if (err == noErr)
- {
- // call our user input dialog function which will return
- // the users choices in the userSettings parameter. I defined
- // the userSettings struct for portability of the information.
- err = GetUserScanInfo(dstPort, &scannerInfo,
- lineArtRes, halfToneRes, grayScaleRes,
- biLevelColorRes, fullColorRes,
- halfToneNames, &userSettings);
-
- if (err == noErr)
- {
- SetCursor(*GetCursor(watchCursor));
-
- // calculate height & width w/ fixmath for accuracy
- height = (FixDiv(FixMul(userSettings.height, FixDiv(userSettings.resolution, 72L)),
- scannerInfo.scanLengthDen) >> 16) * scannerInfo.scanLengthDen;
- width = (FixDiv(FixMul(userSettings.width, FixDiv(userSettings.resolution, 72L)),
- scannerInfo.scanWidthDen) >> 16) * scannerInfo.scanWidthDen;
-
-
- SetRect(&scanRect, 0, 0, width, height);
-
- pixelDepth = scannerInfo.composition[userSettings.compMode].bitsPerPixel;
-
- // we need to go through the hoops and find the actual pixel size
- if (pixelDepth > 8)
- {
- switch (pixelDepth)
- {
- case 0x800000:
- pixelDepth = 32;
- break;
-
- case 0x4000:
- pixelDepth = 16;
- break;
-
- case 0x88:
- pixelDepth = 8;
- break;
- }
-
- }
-
- userSettings.pixelDepth = pixelDepth;
-
- // if compmode is grayscale then we want a gray clut for our
- // offscreen. The System contains handy gray clut resources.
- if (userSettings.compMode == 2)
- cTab = GetCTable(40);
-
- err = NewGWorld(dstPort, pixelDepth, &scanRect, cTab, nil, nil);
-
- if (err == noErr && *dstPort != nil)
- {
- err = DoScan(*dstPort, scannerInfo, &userSettings, scanRect);
- }
-
- SetCursor(&qd.arrow);
-
- }
-
- }
-
- }
- else
- err = paramErr;
-
-
- return err;
- }
-
-
- //----------------------------------------------------------------------
- //
- // DoScan - open connection to scanner, setup scanParams and call
- // scan function.
- //
- //----------------------------------------------------------------------
-
- OSErr DoScan(CGrafPtr dstPort, ScStdFeaturesRec scannerInfo,
- UserSettingsPtr userSettings, Rect scanRect)
- {
- OSErr err = noErr;
- short scanRef;
- short ADFStatus;
- ScScanAreaRec scanParams;
-
- scanRef = 0;
-
- err = ScOpen(&scanRef);
-
- if (err == noErr)
- {
- err = SetupScan(scanRef, scannerInfo, userSettings, scanRect, &scanParams);
-
- // if ADF is specified then check the status
- if (userSettings->inputMethod == kSourceADFItem)
- {
- err = ScVendorUnique(scanRef, scUniqueGetADFStatus, (char *)&ADFStatus);
- if (err == noErr)
- {
- // bit 3 ADF cover open
- if (ADFStatus & 0x08)
- err = kADFCoverOpenErr;
-
- // bit 2 ADF Paper Jam
- if (ADFStatus & 0x04)
- err = kADFPaperJamErr;
-
- // bit 1 ADF No Paper
- if (ADFStatus & 0x02)
- err = kADFNoPaperErr;
-
- }
- }
-
- if (err == noErr)
- {
- err = ScanImage(scanRef, dstPort, scannerInfo, scanParams.scanAreas[0]);
- }
- }
-
- if (scanRef != nil)
- (void)ScClose(scanRef);
-
- return err;
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // GetInputMethods - Determine if a auto document feeder or transparency
- // unit is connected. If either is connected the info
- // will be returned in TPUADFInfo.
- //----------------------------------------------------------------------
-
- OSErr GetInputMethods(Boolean *ADF, Boolean *TPU, ScTPUADFInfoPtr TPUADFInfo)
- {
- OSErr err;
- short scanRef;
- short adfStatus;
- short tpuStatus;
- char *paramPtr;
-
- scanRef = 0;
-
- err = ScOpen(&scanRef);
-
- if (err == noErr)
- {
- err = ScVendorUnique(scanRef, scUniqueGetADFStatus, (char *)&adfStatus);
- err = ScVendorUnique(scanRef, scUniqueGetTPUStatus, (char *)&tpuStatus);
- if (err == noErr)
- {
- // bit 0 - 1 = ADF Not Present
- *ADF = !(adfStatus & 1);
-
- // boolean returned for TPU status
- *TPU = tpuStatus;
-
- err = ScVendorUnique(scanRef, scUniqueGetTPUADFInfo, (char *)TPUADFInfo);
-
- }
-
- }
-
- if (scanRef != nil)
- (void)ScClose(scanRef);
-
- return err;
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // GetScannerInfo - get supported resolutions for each mode and get
- // list of halftone name.
- //
- //----------------------------------------------------------------------
-
- OSErr GetScannerInfo(ScStdFeaturesRec *scannerInfo, ScResPtr *lineArtRes,
- ScResPtr *halfToneRes, ScResPtr *grayScaleRes,
- ScResPtr *biLevelColorRes, ScResPtr *fullColorRes,
- ScHalfTonePtr *halfToneNames)
- {
- OSErr err = noErr;
- ScResPtr resList;
- short scanRef;
- short compMode;
- short numElements;
-
-
- scanRef = 0;
-
- err = ScOpen(&scanRef);
-
- if (err == noErr)
- {
- err = ScGetStdFeatures(scanRef, scannerInfo,
- sizeof(ScStdFeaturesRec));
-
- if (err == noErr)
- {
- for (compMode = scLineArt; compMode <= scFullColor; compMode++)
- {
- if (scannerInfo->composition[compMode].resElements != 0)
- {
- numElements = scannerInfo->composition[compMode].resElements;
- resList = (ScResPtr)NewPtr(numElements * sizeof(short));
-
- if (resList != nil)
- {
- err = ScGetRes(scanRef, compMode, resList);
- if (err == noErr)
- {
- switch (compMode)
- {
- case scLineArt:
- if (lineArtRes != nil)
- *lineArtRes = resList;
- break;
-
- case scHalfTone:
- if (halfToneRes != nil)
- *halfToneRes = resList;
- break;
-
- case scGrayScale:
- if (grayScaleRes != nil)
- *grayScaleRes = resList;
- break;
-
- case scBiLevelColor:
- if (biLevelColorRes != nil)
- *biLevelColorRes = resList;
- break;
-
- case scFullColor:
- if (fullColorRes != nil)
- *fullColorRes = resList;
- break;
-
- default:
- break;
- }
- }
- }
- }
- }
- }
-
- if (scannerInfo->composition[scHalfTone].resElements != 0 && halfToneNames != nil)
- {
- numElements = scannerInfo->composition[scHalfTone].halfToneElements;
-
- *halfToneNames = (ScHalfTonePtr)NewPtr(numElements * sizeof(Str31));
-
- if (*halfToneNames == nil)
- HandleError(MemError(), false);
-
- err = ScGetHalfTones(scanRef, scHalfTone, *halfToneNames);
-
- }
-
- if (scanRef != nil)
- err = ScClose(scanRef);
-
- }
-
- return err;
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // SetupScan - tell the scanner where and how the scan should take place
- //
- //
- //----------------------------------------------------------------------
-
- OSErr SetupScan(short scanRef, ScStdFeaturesRec scannerInfo,
- UserSettingsPtr userSettings, Rect scanRect,
- ScScanAreaRec *scanInfo)
- {
- OSErr err;
- UInt32 pixelDepth;
- short uniqueCode;
-
- // tell scanner which input method we want...FlatBed, ADF, or TPU
- switch (userSettings->inputMethod)
- {
- case kSourceFlatbedItem:
- uniqueCode = 3;
- err = ScVendorUnique(scanRef, scUniqueSetADFPriority, (char *)&uniqueCode);
- break;
-
- case kSourceADFItem:
- uniqueCode = 1;
- err = ScVendorUnique(scanRef, scUniqueSetADFPriority, (char *)&uniqueCode);
- break;
-
- case kSourceTPUItem:
- uniqueCode = 3;
- err = ScVendorUnique(scanRef, scUniqueSetADFPriority, (char *)&uniqueCode);
- break;
-
- default:
- err = paramErr;
- break;
-
- }
-
-
- // change the input method from our popup values to the actual input methods.
- if (err == noErr)
- {
- err = ScVendorUnique(scanRef, scUniqueSetTPUMode, (char *)&userSettings->TPULight);
- if (err == noErr)
- {
- err = ScVendorUnique(scanRef, scUniqueSetTPUNP, (char *)&userSettings->TPUFilm);
- if (err == noErr)
- {
- uniqueCode = userSettings->TPUVendor;
- err = ScVendorUnique(scanRef, scUniqueSetTPUFilmType, (char *)&uniqueCode);
- }
- }
- }
-
- if (scannerInfo.composition[userSettings->compMode].brightnessRange != 0)
- userSettings->brightness |= 0x8000;
-
- if (scannerInfo.composition[userSettings->compMode].contrastRange != 0)
- userSettings->contrast |= 0x8000;
-
- pixelDepth = userSettings->pixelDepth;
-
- // recognizes 24 bit not 32
- if (pixelDepth == 32)
- pixelDepth = 24;
-
- scanInfo->reserved = 0;
- scanInfo->numAreas = 1;
-
- scanInfo->scanAreas[0].reserved = 0;
- scanInfo->scanAreas[0].xDpi = userSettings->resolution;
- scanInfo->scanAreas[0].yDpi = userSettings->resolution;
- scanInfo->scanAreas[0].scanRect = scanRect;
- scanInfo->scanAreas[0].brightness = userSettings->brightness;
- scanInfo->scanAreas[0].contrast = userSettings->contrast;
- scanInfo->scanAreas[0].composition = userSettings->compMode;
- scanInfo->scanAreas[0].bitsPerPixel = pixelDepth;
- scanInfo->scanAreas[0].halfTone = userSettings->ditherPattern;
-
- err = ScSetScanArea(scanRef, scanInfo);
-
- return err;
-
- }
-
-
- //----------------------------------------------------------------------
- //
- // ScanGWorldImage - scan into supplied grafPtr
- //
- //
- //----------------------------------------------------------------------
-
- OSErr ScanImage(short scanRef, CGrafPtr dstPort,
- ScStdFeaturesRec scannerInfo, ScAreaRec scanParams)
- {
- OSErr err;
- PixMapHandle thePix;
- Ptr destImage;
- Ptr buffer = nil;
- Ptr rovingBuffer;
- Ptr destBuffer;
- Rect scanRect;
- long count;
- long dataLen;
- long minDataLen;
- short byteWidth;
- short minReadSize;
- short numScannedRows;
- short destRowBytes;
- short bitsPerPixel;
- short rowNum;
- short channel;
- short index;
-
- thePix = GetGWorldPixMap(dstPort);
- if (LockPixels(thePix))
- {
- SetGWorld(dstPort, nil);
- EraseRect(&dstPort->portRect);
-
- destImage = GetPixBaseAddr(thePix);
- destRowBytes = (**thePix).rowBytes & 0x3FFF;
-
- scanRect = dstPort->portRect;
- bitsPerPixel = scanParams.bitsPerPixel;
-
- if (scanParams.composition == scFullColor)
- byteWidth = ((((8 * (scanRect.right - 1)) / 8) + 1) -
- ((8 * scanRect.left) / 8)) * 3;
- else
- byteWidth = (((bitsPerPixel * (scanRect.right - 1)) / 8) + 1) -
- ((bitsPerPixel * scanRect.left) / 8);
-
- minReadSize = scannerInfo.composition[scanParams.composition].minReadSize;
-
- if (minReadSize > byteWidth)
- minDataLen = byteWidth * ((minReadSize - 1) / byteWidth + 1);
- else
- minDataLen = byteWidth;
-
- // If scanning 24-bit color, allocate a buffer to rearrange pixel data
- if (scanParams.composition == scFullColor)
- buffer = NewPtrClear(minDataLen + byteWidth * 2);
-
- err = MemError();
-
- // Loop until the scan is done
- while (err == noErr)
- {
- // Set maximum amount of data to read at minDataLen
- dataLen = minDataLen;
-
- if (err == noErr && dataLen > 0)
- {
- if (scanParams.composition == scFullColor)
- {
- // Scan a piece of the image
- err = ScDoScan(scanRef, buffer, &dataLen, 0, 0, 0);
-
- numScannedRows = dataLen / byteWidth;
- rowNum = 1;
- rovingBuffer = buffer;
-
- while (rowNum <= numScannedRows)
- {
- for (channel = 1; channel <= 3; channel++)
- {
- for (index = 0; index < (byteWidth / 3) - 1; index++)
- {
- // Convert image to Color QuickDraw format
- destBuffer = (Ptr)((long)destImage + channel + index * 4);
- *destBuffer = *(Ptr)((long)rovingBuffer + index +
- (byteWidth / 3) * (channel - 1));
- }
- }
-
- destImage = (Ptr)((long)destImage + destRowBytes);
- rovingBuffer = (Ptr)((long)rovingBuffer + byteWidth);
-
- rowNum++;
- }
- }
- else
- {
- // Scan a piece of the image
- err = ScDoScan(scanRef, destImage, &dataLen, 0, byteWidth, destRowBytes);
- // If continuing scan, reposition destImage for more
- destImage = (Ptr)((long)destImage + (dataLen / byteWidth) * destRowBytes);
- }
-
- }
-
- }
-
- // If error was scEOS (end of scan), then everything is OK
- if (err == scEOS)
- err = noErr;
-
- // Get rid of the buffer used for 24-bit color
- if (buffer != nil)
- DisposePtr(buffer);
-
- UnlockPixels(thePix);
- }
-
-
- return err;
-
- }